<?php
/**
 * Created by PhpStorm.
 * Author: tqq
 * Email tianqiq@gmail.com
 * Date: 2015-12-11
 */

/**
 * 引入站点配置信息
 */
$config = load_site_config();

//根据域名加载配置信息
function load_site_config() {
    $host = $_SERVER["HTTP_HOST"];
    $config = L('config');
    //是否存在对应host的配
    if (isset($config[$host])) {
        return $config[$host];
    } else {
        if (isset($config['def'])) {
            return $config['def'];
        } else {
            return $config;
        }
    }
}

/**
 * 系统基础配置定义
 **/
define('APP_PATH', isset($config['path']) ? $config['path'] : 'app');
define('DEFAULT_CONTROLLER', isset($config['default_controller']) ? $config['default_controller'] : 'home');
define('E404', isset($config['404']) ? $config['404'] : '/404.html');
define('MODEL_PATH', APP_PATH . '/models'); //模型
define('VIEW_PATH', APP_PATH . '/views'); //视图
define('CONTROLLER_PATH', APP_PATH . '/controllers'); //控制器
define('TOOL_PATH', APP_PATH . '/tools'); //工具
define('REST_METHOD_NAME', '_method'); //由于浏览器不支持put, delete方法， 使用get|post|中的method参数代替
define('TPL', isset($config['tpl']) ? $config['tpl'] : false); //是否使用模板引擎

if (isset($config['debug']) && $config['debug']) {
    set_exception_handler('fox_error_handler');
    set_error_handler('fox_error_handler');
    register_shutdown_function('fox_shutdown');
}

function fox_shutdown() {
    $error = error_get_last();
    if ($error && $error['type'] != E_NOTICE) {
        fox_error_show($error['message'], array($error), null);
    }
}

function fox_error_handler($errno_exp, $errstr = '', $errfile = '', $errline = '') {

    if ($errno_exp == E_NOTICE) {
        return;
    }
    if (is_numeric($errno_exp)) {
        $msg = $errstr;
        $traces = debug_backtrace();
    } else {
        $msg = $errno_exp->getMessage();
        $traces = $errno_exp->getTrace();
        $first['file'] = $errno_exp->getFile();
        $first['line'] = $errno_exp->getLine();
        $first['class'] = '';
        $first['function'] = '';
        array_unshift($traces, $first);
    }
    fox_error_show($msg, $traces, $errno_exp);
}

function fox_error_show($msg, $traces ,$errno_exp ) {
    echo "<!DOCTYPE html><html><head><style>
        h1{color:#f00;} ul{list-style: none;} p,pre{text-indent:0em; background-color:#FFFFCC;padding:1em;} td{border:1px solid #ccc; padding:0.5em;    background-color: #FFFFCC } table{   border-collapse: collapse;}
    </style></head><body><h1>Error</h1><p>";
    echo $msg;
    echo "</p>";
    if($errno_exp instanceof PDOException && $GLOBALS['_last_db_']){
        $GLOBALS['_last_db_']->print_error();
    }
    echo "<h1>Traces</h1><table><tr><td>NO.</td><td>File</td> <td>Line</td><td>Class</td><td>Function</td></tr>";
    for ($i = 0; $i < count($traces); $i++) {
        $value = $traces[$i];
        $index = $i + 1;
        if (!empty($value) && isset($value['file'])) {
            $file = str_replace($_SERVER['DOCUMENT_ROOT'], '', $value['file']);
            echo "<tr><td>$index</td><td>$file</td><td>$value[line]</td><td>" . (isset($value['class']) ? $value['class'] : '') . "</td><td>" . (isset($value['function']) ? $value['function'] : '') . "</td></tr>";
        }
    }
    echo "</table></body></html>";
    die();
}

//运行框架
defined('ROOT') ? Fox::getInstance()->run() : die('error! ROOT undefined');

/*** MVC核心 beg***/

/**
 * 显示一个视图文件 $view 可以是路径，不需要.php后缀
 * @param $view
 */
function view($view) {
    fox_tpl_include($view);
    Fox::getInstance()->end();
}

function fox_tpl_include($view) {
    $view = strtolower($view);
    $path = combine_paths(ROOT, VIEW_PATH, $view . '.php');
    if (TPL) {
        $cache_path = combine_paths(ROOT, VIEW_PATH, '_cache');
        if (!is_dir($cache_path)) {
            mkdir($cache_path);
        }
        $cache_file_name = trim(str_replace('\\', '.', combine_paths($view)), '.') . '.php';
        $cache_file_path = combine_paths($cache_path, $cache_file_name);
        if (!is_file($cache_file_path) || filemtime($cache_file_path) < filemtime($path)) {
            file_put_contents($cache_file_path, compiler(file_get_contents($path)));
        }
        $path = $cache_file_path;
    }
    extract(view_data(null));
    include $path;
}

function compiler($tpl) {

    $tokens = [
        '/@(if)(\s*\(.*\))/' => '<?php $1$2 { ?>',
        '/@(elseif)(\s*\(.*\))/' => '<?php }$1$2 { ?>',
        '/@(else)/' => '<?php } $1 { ?>',
        '/@(while)(\s*\(.*\))/' => '<?php $1$2 { ?>',
        '/@(foreach)(\s*\(.*\))/' => '<?php $1$2 { ?>',
        '/@(for)(\s*\(.*\))/' => '<?php $1$2 { ?>',
        '/@(include)(\s*\(.*\))/' => '<?php fox_tpl_include$2 ; ?>',
        '/!@\{(.+?)\}/' => '<?php $1; ?>',
        '/@(end)/' => '<?php } ?>',
        '/@\{(.+?)\}/' => '<?php echo $1; ?>',
        '/@(\w+)\.(\w+)/' => '<?php echo \$$1[\'$2\']; ?>',
        '/@(\w+)-(\w+)/' => '<?php echo \$$1->$2; ?>',
        '/@(\w+)/' => '<?php echo \$$1; ?>'
    ];

    foreach ($tokens as $key => $val) {
        $tpl = preg_replace($key, $val, $tpl);
    }

    return $tpl;
}

/**
 * @desc 输出js脚本，http头：application/javascript
 * @param $js
 */
function js($js) {
    response($js, 'application/javascript');
}

/**
 * 什么都不输出
 */
function none() {
    html('');
}

/**
 * 通过输出js脚本弹出提示，并跳转到指定url
 * @param $message
 * @param string $url
 */
function alert($message, $url = '#') {
    html("<script>alert('$message');location.href='$url';</script>");
}

/**
 * 输出一段纯文本 http头：text/plain
 * @param $text
 */
function text($text) {
    response($text, "text/plain");
}

/**
 * 输出json http头：application/json
 * @param $data
 */
function json($data) {
    response(json_encode($data), 'application/json');
}

/**
 * 输出html http头：text/html
 * @param $html
 */
function html($html) {
    response($html, false);
}

/**
 * 重定向到指定url
 * @param $url
 * @param int $code 状态码，默认302
 */
function redirect($url, $code = 302) {
    if ($code == 301) {
        header('HTTP/1.1 301 Moved Permanently');
    } else {
        header('HTTP/1.1 302 Found');
    }
    header('Cache-Control:no-cache');
    header("location:$url");
}

/**
 * 输出指定数据和http头
 * @param $data
 * @param $content_type
 */
function response($data, $content_type) {
    Fox::getInstance()->end();
    if ($content_type !== false) {
        header("Content-Type: $content_type");
    }
    echo $data;
}

/**
 * 重写到指定的url
 * @param $url
 */
function rewrite($url) {
    Fox::getInstance()->rewrite($url);
}

/**
 * 重定向到指定的url或者闭包函数
 * @param  [type] $url 匹配的url
 * @param  [type] $to  重定向到指定的url，或者闭包函数
 * @return [type]      无返回值
 */
function route($url, $handler = null) {
    global $config;
    if (!isset($config['route'])) {
        $config['route'] = [];
    }
    if ($handler === null) {
        $config['route'] = array_merge($config['route'], $url);
    } else {
        if (is_array($url)) {
            foreach ($url as $key) {
                $config['route'][$key] = $handler;
            }
        } else {
            $config['route'][$url] = $handler;
        }
    }
}

/**
 * 设置一个数据到视图数据，通过G()函数获取
 * @param $key
 * @param $val
 */
function S($key, $val) {
    view_data($key, $val);
}

/**
 * 从视图数据中， 获取数据
 * @param $key
 * @return mixed
 */
function G($key) {
    return view_data($key);
}

/**
 * 获取一个模型
 * @param $model
 * @param null $construct_args
 * @return mixed|object
 */
function M($model, $construct_args = null) {
    return L(combine_paths(MODEL_PATH, $model), $construct_args);
}

/**
 * 获取一个工具
 * @param $tool
 * @return mixed|object
 */
function T($tool, $construct_args = null) {
    return L(combine_paths(TOOL_PATH, $tool), $construct_args);
}

function ns() {
    $namespace = join('\\', func_get_args());
    return preg_replace('/\\\+|\/+/', '\\', $namespace);
}

function combine_paths() {
    $paths = join(DIRECTORY_SEPARATOR, func_get_args());
    return preg_replace('/\\\+|\/+/', DIRECTORY_SEPARATOR, $paths);
}

/**
 * 加载指定路径的文件，只加载一次。 不需要.php或者.class.php后缀，如果是.class.php会实例化对象返回，如果include文件中包涵return 值，会返回该值。如果未找到文件，返回null
 * @param $path 不需要.php或者.class.php后缀
 * @param null $construct_args
 * @return mixed|object
 */
function L($path, $construct_args = null) {
    static $loads = [];
    $class_name = ns($path);
    $file_path = combine_paths(ROOT, $path);
    if (!isset($loads[$path])) {
        if (is_file($file_path . '.php')) {
            return $loads[$path] = include_once $file_path . '.php';
        } else if (is_file($file_path . '.class.php')) {
            include_once $file_path . '.class.php';
            $loads[$path] = '__class__';
            return is_null($construct_args) ? new $class_name() : (new ReflectionClass($class_name))->newInstanceArgs($construct_args);
        }
        throw new Exception( "加载 $file_path 失败,文件未找到！");
    } else {
        return $loads[$path] === '__class__' ?
            (is_null($construct_args) ? new $class_name() : (new ReflectionClass($class_name))->newInstanceArgs($construct_args))
            : $loads[$path];
    }
}

/**
 * 视图数据存储
 * @param $key
 * @param $val
 */
function view_data($key, $val = null) {
    static $view_data = [];
    if ($key == null) {
        return $view_data;
    }
    if ($val === null) {
        return $view_data[$key];
    }
    $view_data[$key] = $val;
}

/**
 * 将客户端post过来的数据通过json_decode转换并返回
 * @param $assoc
 * @return object
 */
function J($assoc = true) {
    static $json;
    return $json ?: $json = json_decode(file_get_contents('php://input'), $assoc);
}

/**
 * Class Fox MVC核心
 */
class Fox {

    /**
     * @var 路由
     */
    private $route;

    private static $instance;

    public static function getInstance() {
        if (!self::$instance) {
            self::$instance = new Fox();
        }
        return self::$instance;
    }

    private function __construct() {
        $this->route = new Route();
    }

    private $is_response = false;

    public function end() {
        $this->is_response = true;
    }

    public function run() {
        $this->ini();
        $this->route();
    }

    public function rewrite($url) {
        $this->route->start($url);
        $this->route();
    }

    private function ini() {
        global $config;
        //加载需要加载的初始化文件
        if (isset($config['ini_files']) && is_array($config['ini_files'])) {
            foreach ($config['ini_files'] as $file) {
                L($file);
            }
        }
        //实例化route
        $this->route->start();
    }

    private function include_controller($dir, $ctr) {
        $ctr = ucfirst($ctr);
        $path = combine_paths(ROOT,CONTROLLER_PATH, $dir, $ctr . 'Controller.php');
        return is_file($path) ? include_once($path) : false;
    }

    private function real_action($controller, $req_controller_name, $req_action, $err_controller) {
        $http_method = $this->route->get_http_method();
        if ($err_controller) {
            $real_action = method_exists($controller, '_ec') ? '_ec' : false;
        } else if (empty($req_controller_name)) {
            $real_action = method_exists($controller, '_def') ? '_def' : false;
        }else if(method_exists($controller, '_' . $http_method . '_' . $req_action)){
            $real_action  =  '_' . $http_method . '_' . $req_action;
        }else if (method_exists($controller, $req_action)) {
            $real_action = $req_action;
        }else if (method_exists($controller, '_' . $http_method)) {
            $real_action = '_' . $http_method;
        } else {
            $real_action = method_exists($controller, '_def') ? '_def' : false;
        }
        return $real_action;
    }

    private $methods = array('_def', '_post', '_put', '_get', '_delete', '_patch', '_head');

    private function real_paths($real_action) {
        $req_paths = $this->route->get_paths();
        if ($real_action == '_ec') {
            $real_paths = $req_paths;
        } else if (in_array($real_action, $this->methods)) {
            $real_paths = array_slice($req_paths, 1);
        } else {
            $real_paths = array_slice($req_paths, 2);
        }
        return $real_paths;
    }

    private function route() {

        $req_controller_name = $this->route->get_controller();
        $real_controller_name = $this->route->get_controller() ?: DEFAULT_CONTROLLER; //获取请求的controller名字
        $req_action = $this->route->get_action(); //请求的action名字;
        $dir = $this->route->get_dir();

        if ($err_controller = !$this->include_controller($dir, $real_controller_name)) {
            //尝试引入Controller文件，如果没成功引入，再引入默认controller。
            $this->include_controller($dir, DEFAULT_CONTROLLER);
            $real_controller_name = DEFAULT_CONTROLLER;
        }

        $controller_class = ns(CONTROLLER_PATH, $dir, $real_controller_name . 'Controller');

        if (substr($req_action, 0, 1) != '_' && class_exists($controller_class, false)) {
            $controller = new $controller_class();
            $real_action = $this->real_action($controller, $req_controller_name, $req_action, $err_controller);
            if ($real_action !== false) {
                $this->exe_action($controller, $real_controller_name, $real_action, $this->real_paths($real_action));
                return;
            }
        }

        $this->e404();
    }

    private function e404() {
        if (E404) {
            redirect(E404 . "?ref=$_SERVER[REQUEST_URI]", 302);
        } else {
            header('HTTP/1.1 404 Not Found');
            header("status: 404 Not Found");
            echo 'HTTP 404 Not Found';
        }
        die();
    }

    private function exe_action($controller, $controller_name, $action_name, $paths) {
        if (method_exists($controller, '_before')) {
            $controller->_before($action_name, $paths);
        }
        $controller->$action_name(empty($paths) ? false : $paths[0], array_slice($paths, 1));
        $dir = $this->route->get_dir();
        if (!$this->is_response) {
            view(combine_paths($dir, "${controller_name}_${action_name}"));
        }
        if (method_exists($controller, '_after')) {
            $controller->_after($action_name, $paths);
        }
    }

}

/**
 * Class Route 路由
 */
class Route {

    private $url;

    public function start($url = false) {
        $this->url = trim($this->apply_user_route($url !== false ? $url : $this->get_url_path()),'/');
        $this->parse();
    }

    /**
     * 无论有没有开启伪静态，获取纯mvc路径url
     * domain.com/control/action 或者 domain.com/index.php/control/action
     * @return string
     */
    public function get_url_path() {
        $name = $_SERVER['SCRIPT_NAME'];
        $url = $_SERVER['REQUEST_URI'];
        if (strpos($url, $name) === 0) {
            $url = substr($url, strlen($name));
        }
        if (($pos = stripos($url, '?')) !== false) {
            $url = substr($url, 0, $pos);
        }
        return trim($url, '/');
    }

    private function apply_user_route($url) {
        global $config;
        $routes = $config['route'];
        if (!empty($routes)) {
            //实际请求的http method
            $req_method = $this->get_http_method();
            foreach ($routes as $source => $to) {
                $to = $this->parse_url_rule($source, $to, $req_method, $url);
                if ($to !== false) {
                    $url = $to;
                    break;
                }
            }
        }
        return $url;
    }

    private function parse_url_rule($source, $to, $req_method, $url) {

        $source = str_replace('/', '\\/', $source); //将/（url分隔符）替换为\/避免正则出错
        $parts = explode('@', $source);
        $source = count($parts) == 1 ? $parts[0] : $parts[1]; //去掉method的url模式
        $method = strtolower(count($parts) == 1 ? '' : $parts[0]); //需要匹配的 http method
        if ((empty($method) || $method == $req_method) && preg_match("/^$source$/i", $url, $matchs)) {
            if (is_string($to)) {
                for ($i = 1; $i < count($matchs); $i++) {
                    $to = str_replace("($i)", $matchs[$i], $to);
                }
                return $to;
            } else {
                array_shift($matchs);
                call_user_func_array($to, $matchs); //如果是闭包函数路由， 直接调用函数，并结束流程
                die();
            }
        }
        return false;
    }

    public function get_http_method() {
        static $method;
        if (empty($method)) {
            $method = strtolower(isset($_REQUEST[REST_METHOD_NAME]) ? $_REQUEST[REST_METHOD_NAME] : $_SERVER['REQUEST_METHOD']);
            //去掉rest请求方法参数
            unset($_GET[REST_METHOD_NAME]);
            unset($_POST[REST_METHOD_NAME]);
            unset($_REQUEST[REST_METHOD_NAME]);
        }
        return $method;
    }

    private $paths;

    private $dir;

    /**
     * 分析url
     */
    private function parse() {
        $paths = explode('/', $this->url);
        $controller_path = ROOT . '/' . CONTROLLER_PATH;
        $dir = '';
        for ($i = 0, $len = count($paths); ($i < $len && !empty($paths[$i]) && is_dir(combine_paths($controller_path, $dir, $paths[$i]))); $i++) {
            $dir .= '/' . $paths[$i];
        }
        $this->dir = ltrim($dir, '/');
        $this->paths = empty($this->dir) ? $paths : array_slice($paths, $i);
    }

    /**
     * 获取controller路径，即controllers目录下子目录，如果没子目录则返回空，
     * @return mixed
     */
    public function get_dir() {
        return $this->dir;
    }

    /**
     * 获取controller名字 没有返回空
     * @return string
     */
    public function get_controller() {
        return empty($this->paths) ? '' : $this->paths[0];
    }

    /**
     * 获取action名字，没有返回空
     * @return null
     */
    public function get_action() {
        return count($this->paths) > 1 ? $this->paths[1] : '';
    }

    /**
     * 获取分析后的url路径数组
     * @return mixed
     */
    public function get_paths() {
        return $this->paths;
    }
}

/*** MVC核心 end***/

/*** 正则验证类 beg***/

/**
 * 快捷函数，判断val是否是指定的类型
 * @param $type
 * @param $val
 * @return bool
 */
function I($type, $val) {
    return V::is($type, $val);
}

/**
 * Class v 使用方便，扩展方便的验证类
 */
class V {

    private static $types = [
        'email' => '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/',
        'phone' => '/^((\(\d{2,3}\))|(\d{3}\-))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$/',
        'mobile' => '/^((\(\d{2,3}\))|(\d{3}\-))?1\d{9}$/',
        'url' => '/^https?:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\'=>+!]*([^<>\"\"])*$/',
        'id' => '/^\d{15}(\d{2}[A-Za-z0-9])?$/',
        'currency' => '/^\d+(\.\d+)?$/',
        'number' => '/^\d+$/',
        'qq' => '/^[1-9]\d{4,9}$/',
        'int' => '/^[-\+]?\d+$/',
        'double' => '/^[-\+]?\d+(\.\d+)?$/',
        'en' => '/^[A-Za-z]+$/',
        'ch' => '/^[\u0391-\uFFE5]+$/',
        'name' => '/^[a-z]\w{5,}$/i',
        'ip' => '/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){3}$/',
    ];

    /**
     * 数据验证函数
     * @param $type 如果type参数以.（点）开头，该参数可以为空
     * @param $val
     * @return int
     */
    public static function is($type, $val) {
        $dot = substr($type, 0, 1) == '.';
        if ($dot) {
            if (empty($val)) {
                return true;
            }
            $type = substr($type, 1);
        }
        $test = self::$types[$type];
        return is_string($test) ? preg_match($test, $val) : $test($val);
    }

    /**
     * 扩展验证规则
     * @param $type 扩展类型名字
     * @param $reg_or_fun
     * @internal param 可以为一个正则表达式 $fun ，或者函数
     */
    public static function extend($type, $reg_or_fun) {
        self::$types[$type] = $reg_or_fun;
    }

}

/*** 正则验证类 end***/

/*** 简单数据库操作类 begin***/

/**
 * 获取DB的快捷函数
 * @param bool|false $tableName 当前操作的tableName
 * @param $db |def 当前操作的db
 * @return DataBase
 */
function D($tableName = '', $db = 'def') {
    global $config;
    static $dbs = [];
    if (!isset($dbs[$db])) {
        $dbs[$db] = [];
    }
    if (!isset($dbs[$db][$tableName])) {
        $dbs[$db][$tableName] = new DataBase(isset($config['db']['dsn']) ? $config['db'] : $config['db'][$db]);
    }

    return $dbs[$db][$tableName]->table($tableName);
}

/**
 * Class DataBase 简单方便的数据操作类
 */
class DataBase {

    public $pdo;

    private $table = '_fox_';

    function __construct($cf) {
        $this->pdo = self::_poll($cf); // new PDO($cf['dsn'], $cf['user'], $cf['pwd'], $cf['options']);
    }

    private static function _poll($cf) {
        static $exist_pdo = [];
        if (!isset($exist_pdo[$cf['dsn']])) {
            $pdo = isset($cf['options']) ? (new PDO($cf['dsn'], $cf['user'], $cf['pwd'], $cf['options'])) :
                (new PDO($cf['dsn'], $cf['user'], $cf['pwd']));
            $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $pdo->exec("set names " . (isset($cf['charset']) ? $cf['charset'] : 'utf8'));
            $exist_pdo[$cf['dsn']] = $pdo;
        }
        return $exist_pdo[$cf['dsn']];
    }

    /**
     * 开启事务
     */
    public function begin_transaction() {
        $this->pdo->beginTransaction();
    }

    /**
     * 提交事务
     */
    public function commit() {
        $this->pdo->commit();
    }

    /**
     * 回滚事务
     */
    public function roll_back() {
        $this->pdo->rollBack();
    }

    /**
     * 设置当前操作的表
     * @param $table
     * @return $this
     */
    public function table($table) {
        $this->table = $table;
        return $this;
    }

    /**
     * 插入数据到数据库
     * @param $data
     * @return int|false
     */
    public function insert($data) {
        $inputs = [];
        $fields = [];
        $qs = [];
        foreach ($data as $key => $val) {
            $fields[] = "`$key`";
            $qs[] = '?';
            $inputs[] = $val;
        }
        $sql = "insert into $this->table(" . join(',', $fields) . ') values(' . join(',', $qs) . ')';
        return $this->row_count($sql, $inputs);
    }

    /**
     * 更新数据库记录
     * @param $data
     * @param $where id或者where条件
     * @param bool|false $inputs sql参数值
     * @return int|false
     */
    public function update($data, $where, $inputs = false) {
        $arr = [];
        $fields = [];
        foreach ($data as $key => $val) {
            $fields[] = " `$key` = ? ";
            $arr[] = $val;
        }
        $where = $this->parse_where($where);
        $sql = "update $this->table set " . join(',', $fields) . " where $where";
        return $this->row_count($sql, is_array($inputs) ? array_merge($arr, $inputs) : $arr);
    }

    private function row_count($sql, $inputs) {
        $result = $this->execute($sql, $inputs);
        return $result === false ? false : $result->rowCount();
    }

    private function parse_where($where) {
        return is_numeric($where) ? " `id` = $where " : $where;
    }

    /**
     * 删除数据库记录
     * @param $where id或者where条件
     * @param bool|false $inputs sql参数值
     * @return int|false
     */
    public function delete($where, $inputs = false) {
        $where = $this->parse_where($where);
        $sql = "delete from $this->table where $where";
        return $this->row_count($sql, $inputs);
    }

    /**
     * 获取数据库一条记录
     * @param $where id或者where条件
     * @param bool|false $inputs sql参数值 如果该值为字符串，则视为 $field
     * @param string $field
     * @return val|false
     */
    public function get($where, $inputs = false, $field = '*') {
        if (is_string($inputs)) {
            $field = $inputs;
            $inputs = '';
        }
        $where = $this->parse_where($where);
        $sql = "select $field from  $this->table where $where limit 1";
        $result = $this->execute($sql, $inputs);
        return $result === false ? false : $result->fetch(PDO::FETCH_ASSOC);
    }

    /**
     * 获取第一行第一个值
     * @param $where id或者where条件
     * @param bool|false $inputs sql参数值
     * @param string $field
     * @return val|bool
     */
    public function value($where, $inputs = false, $field = '*') {
        if (is_string($inputs)) {
            $field = $inputs;
            $inputs = '';
        }
        $where = $this->parse_where($where);
        $sql = "select $field from  $this->table where $where limit 1";

        $result = $this->execute($sql, $inputs);
        if ($result === false) {
            return false;
        }
        $ret = $result->fetch(PDO::FETCH_NUM);
        return $ret === false ? false : $ret[0];
    }

    /**
     * 根据where条件获取记录集
     * @param $where where条件
     * @param bool|false $inputs sql参数值
     * @param string $field
     * @return array|false
     */
    public function find($where, $inputs = false, $field = '*') {
        if (is_string($inputs)) {
            $field = $inputs;
            $inputs = '';
        }
        $sql = "select $field from  $this->table where $where";
        return $this->select($sql, $inputs);
    }

    /**
     * 根据sql语句获取所有记录
     * @param $sql
     * @param bool|false $inputs
     * @return array|false
     */
    public function select($sql, $inputs = false) {
        $result = $this->execute($sql, $inputs);
        return $result === false ? false : $result->fetchAll(PDO::FETCH_ASSOC);
    }

    private $result;

    /**
     * 执行一条sql语句
     * @param $sql
     * @param $inputs sql参数值
     * @return PDOStatement|false
     */
    public function execute($sql, $inputs = false) {
        $GLOBALS['_last_db_'] =  $this;
        $this->sql = $sql;
        $this->inputs = $inputs;
        if (($this->result = $this->pdo->prepare($sql)) !== false) {
            is_array($inputs) ? $this->result->execute($inputs) : $this->result->execute();
        }
        return $this->result;
    }

    private $sql;

    private $inputs;

    public function print_error() {
        echo '<pre>SQL Info: ';
        print_r(array(
            'sql' => $this->sql,
            'inputs' => $this->inputs
        ));
        echo '</pre>';
    }

    /**
     * 数据库最后id
     * @return string
     */
    public function last_id() {
        return $this->pdo->lastInsertId();
    }

    private $error_info;

    /**
     * 数据库最后语句的错误信息
     * @return mixed
     */
    public function error_info() {
        return $this->error_info;
    }

    public function __destruct() {
        if ($this->pdo) {
            unset($this->pdo);
        }
        if ($this->result) {
            unset($this->result);
        }
    }

}

/*** 简单数据库操作类 end***/